
#pragma once

#include "atr/containers/access.hpp"
#include "atr/containers/modifiers.hpp"

namespace atr {

/**
 * @brief   Class providing iterator-like API for containers elements
 * @details Class contains methods such as next, prev to freely navigate throu
 *          container types.
 *
 * @tparam  class Prev is sequence 'begind' us.
 * @tparam  class Next is sequence 'in front' of us and additionally
 *          current element.
 *
 * @todo    Add ability to mve forward/backward more then one position at one.
 *          It will look like 'iterator::next<5>'.
 */
template <typename Prev, typename Next>              struct iterator;

/**
 * @brief   Helper class providing iterator-like API for containers elements -
 *          partial specialization.
 * @details Class contains methods such as next, prev to freely navigate throu
 *          container types.
 *
 * @tparam  template <class ...> class Base is template for container that
 *          this iterator is representing
 * @tparam  class ... Prev is sequence 'behind' us.
 * @tparam  class ... Next is sequence 'in front' of us and additionally
 *          current element.
 *
 * @todo    Add ability to mve forward/backward more then one position at one.
 *          It will look like 'iterator::next<5>'.
 */
template <template <class ...> class Base, typename ... Prevs
                                         , typename ... Nexts>
struct iterator<Base<Prevs...>, Base<Nexts...>>;

/**
 * @brief   Namespace only for internal use of atr library
 * @details Please don't use this namespace outside the atr library.
 *          IF you REALLY need to - do it with special care.
 */
namespace __ {

/**
 * @brief   Helper class alloving for type dereference
 * @details This implementation uses __::__access<...> for accessing first
 *          element in sequence and then dereference it. Because od that we
 *          aren't using any container specific operation.This implementation
 *          requires that atleast one element is in sequence.
 *          For case with no elements see below.
 */
template <typename ... Nexts>
struct __iterator_type
{
    /** Result type for dereference operation */
    using type = typename __::__access<Nexts...>::front;
};

/**
 * @brief   Helper class alloving for type dereference - no object
 * @details This case is used when sequence is empty (e.g. atr::list<>). For
 *          case with non zero elements count please see above.
 */
template <>
    struct __iterator_type<> {};

/**
 * @brief   Helper class alloving for operation 'prev'
 * @details Class allovs for operation 'prev' on container (if it's possible)
 *
 * @tparam  class Prev is sequence 'begind' us.
 * @tparam  class Next is sequence 'in front' of us and additionally
 *          current element.
 *
 * @todo    Add ability to mve forward/backward more then one position at one.
 *          It will look like '__iterator_prev<Prev, Next, 5>'.
 */
template <typename Prev, typename Next>             struct __iterator_prev {};

/**
 * @brief   Helper class alloving for operation 'prev' - partial specialization
 * @details Class allovs for operation 'prev' on container (if it's possible).
 *          This specialization handles case, when we cannot go back because we
 *          are at the front of containers' sequence - 'head'
 *
 * @tparam  template <class ...> class Base is template for container that
 *          this iterator is representing
 * @tparam  class ... Next is sequence 'in front' of us and additionally
 *          current element.
 *
 * @todo    Add ability to mve forward/backward more then one position at one.
 *          It will look like '__iterator_prev<Prev, Next, 5>'.
 */
template <template <class ...> class Base, typename ... Nexts>
    struct __iterator_prev<Base<>, Base<Nexts...>> {};

/**
 * @brief   Helper class alloving for operation 'prev' - partial specialization
 * @details Class allovs for operation 'prev' on container (if it's possible).
 *          This specialization handles case, when we can go back because we
 *          aren't at the front of containers' sequence. This implementation
 *          uses __::__modifiers for removing last element prom 'Prev' sequence
 *          and __:__access for accessing this one element and then putting it
 *          into 'Nexts' sequence. Because od that we aren't using any container
 *          specific operation.
 *
 * @tparam  template <class ...> class Base is template for container that
 *          this iterator is representing
 * @tparam  class ... Prev is sequence 'behind' us.
 * @tparam  class ... Next is sequence 'in front' of us and additionally
 *          current element.
 *
 * @todo    Add ability to move forward/backward more then one position at one.
 *          It will look like '__iterator_prev<Prev, Next, 5>'.
 */
template <template <class ...> class Base, typename ... Prevs
                                         , typename ... Nexts>
struct __iterator_prev<Base<Prevs...>, Base<Nexts...>>
{
    /** Result type for prev operation */
    using prev = iterator<typename __::__modifiers<Base, Prevs...>::pop_back
                         ,Base<typename __::__access<Prevs...>::back,Nexts...>>;
};

/**
 * @brief   Helper class alloving for operation 'next'
 * @details Class allovs for operation 'next' on container (if it's possible)
 *
 * @tparam  class Prev is sequence 'begind' us.
 * @tparam  class Next is sequence 'in front' of us and additionally
 *          current element.
 *
 * @todo    Add ability to mve forward/backward more then one position at one.
 *          It will look like '__iterator_next<Prev, Next, 5>'.
 */
template <typename Prev, typename Next>             struct __iterator_next {};

/**
 * @brief   Helper class alloving for operation 'next' - partial specialization
 * @details Class allovs for operation 'next' on container (if it's possible).
 *          This specialization handles case, when we cannot go further because
 *          we are at the end of containers' sequence - 'end'
 *
 * @tparam  template <class ...> class Base is template for container that
 *          this iterator is representing
 * @tparam  class ... Prevs is sequence 'behind' us.
 *
 * @todo    Add ability to mve forward/backward more then one position at one.
 *          It will look like '__iterator_next<Prev, Next, 5>'.
 */
template <template <class ...> class Base, typename ... Prevs>
    struct __iterator_next<Base<Prevs...>, Base<>> {};

/**
 * @brief   Helper class alloving for operation 'next' - partial specialization
 * @details Class allovs for operation 'next' on container (if it's possible).
 *          This specialization handles case, we can go forward because we
 *          aren't at the end of containers' sequence. This implementation uses
 *          __::__access to access to first element of Nexts and __:__modifiers
 *          to remove first element of Nexts. Because od that we aren't using
 *          any container specific operation.
 *
 * @tparam  template <class ...> class Base is template for container that
 *          this iterator is representing
 * @tparam  class ... Prev is sequence 'behind' us.
 * @tparam  class ... Next is sequence 'in front' of us and additionally
 *          current element.
 *
 * @todo    Add ability to mve forward/backward more then one position at one.
 *          It will look like '__iterator_next<Prev, Next, 5>'.
 */
template <template <class ...> class Base, typename ... Prevs
                                         , typename ... Nexts>
struct __iterator_next<Base<Prevs...>, Base<Nexts...>>
{
    /** Result type for next operation */
    using next = iterator<Base<Prevs..., typename __::__access<Nexts...>::front>
                         ,typename __::__modifiers<Base, Nexts...>::pop_front>;
};

} // namespace __

/**
 * @brief   Implementation of helper class providing iterator-like API for
 *          containers elements - partial specialization.
 * @details Class contains methods such as next, prev to freely navigate throu
 *          container types.
 *
 * @tparam  template <class ...> class Base is template for container that
 *          this iterator is representing
 * @tparam  class ... Prev is sequence 'begind' us.
 * @tparam  class ... Next is sequence 'in front' of us and additionally
 *          current element.
 *
 * @todo    Add ability to mve forward/backward more then one position at one.
 *          It will look like 'iterator::next<5>'.
 */
template <template <class ...> class Base, typename ... Prevs
                                         , typename ... Nexts>
struct iterator<Base<Prevs...>, Base<Nexts...>>
    : public __::__iterator_type<Nexts...>
    , public __::__iterator_prev<Base<Prevs...>, Base<Nexts...>>
    , public __::__iterator_next<Base<Prevs...>, Base<Nexts...>>
{
    /**
     * Result type for 'begin' operation.
     * It's the fastert way to do that.
     */
    using begin = iterator<Base<>, Base<Prevs..., Nexts...>>;

    /**
     * Result type for 'end' operation.
     * It's the fastert way to do that.
     */
    using end   = iterator<Base<Prevs..., Nexts...>, Base<>>;
};

} // namespace atr